<template>
  <div class="pdf-image-container" ref="container">
    <img v-if="isLoading" src="~@/assets/images/loading.gif" alt="loading">
    <div v-else-if="isError" class="load-error">加载图像失败</div>
    <canvas v-else ref="canvas" :style="`height: ${height}px`" />
  </div>
</template>

<script>
import * as pdfjsLib from "pdfjs-dist";
import "pdfjs-dist/webpack.mjs";
export default {
  props: {
    src: {
      type: String,
      required: true,
    },
    fixedWidth: {
      type: Boolean,
      default: false,
    },
    initialHeight: {
      type: Number,
      default: 100,
    },
  },
  data() {
    return {
      isLoading: true,
      isError: false,
      height: this.initialHeight,
      /** @type {pdfjsLib.PDFPageProxy} */
      pageOne: null,
      viewWidth: 0,
      viewHeight: 0,
    };
  },
  methods: {
    clearPDF() {
      /** @type {HTMLCanvasElement} */
      const canvas = this.$refs.canvas;
      if (!this.pageOne || !canvas) {
        return;
      }
      const ctx = canvas.getContext("2d");
      ctx.clearRect(0, 0, canvas.width, canvas.height);
    },
    loadPdf() {
      if (!this.src) {
        return;
      }
      this.clearPDF();
      this.isLoading = true;
      const loadingTask = pdfjsLib.getDocument(this.src);
      // pdfjsLib.GlobalWorkerOptions.workerSrc = ;
      loadingTask.promise
        .then(async (pdf) => pdf.getPage(1))
        .then((page) => {
          this.pageOne = page;
          requestAnimationFrame(()=> {
            // 等待 canvas 挂载
            this.drawPDF();
          });
        })
        .catch((err) => {
          console.log(err);
          this.isError = true;
        })
        .finally(() => {
          this.isLoading = false;
        });
    },
    drawPDF() {
      /** @type {HTMLCanvasElement} */
      const canvas = this.$refs.canvas;
      if (!this.pageOne || !canvas) {
        return;
      }
      const ctx = canvas.getContext("2d");
      var scale = 1.5;
      var viewport = this.pageOne.getViewport({ scale: scale });
      // Support HiDPI-screens.
      var outputScale = window.devicePixelRatio || 1;

      canvas.width = Math.floor(viewport.width * outputScale);
      canvas.height = Math.floor(viewport.height * outputScale);

      this.viewWidth = viewport.width;
      this.viewHeight = viewport.height;

      var transform =
        outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : null;

      this.pageOne.render({
        canvasContext: ctx,
        transform: transform,
        viewport: viewport,
      });
      this.resize();
    },
    resize() {
      const width = this.$refs.container.clientWidth;
      if (!width) {
        throw new Error('"PDFImage" container width is needed');
      }
      this.height = this.viewHeight * (width / this.viewWidth);
    },
  },
  watch: {
    src: {
      immediate: true,
      handler: "loadPdf",
    },
  },
  mounted() {
    if (this.fixedWidth) {
      return;
    }
    let flag = true;
    const observer = new ResizeObserver(() => {
      // resize调用也会触发该回调一次
      // 由此触发的回调不执行
      //? 更好的方法？
      flag = !flag;
      if (flag) {
        return;
      }
      requestAnimationFrame(() => {
        this.resize();
      });
    });
    observer.observe(this.$refs.container);
    this.disconnectResizeObserver = observer.disconnect;
  },
  beforeDestroy() {
    this.disconnectResizeObserver?.();
  },
};
</script>

<style lang="less">
.pdf-image-container {
  position: relative;
  .load-error {
    position: absolute;
    top: 10px;
    left: 10px;
    font-size: 12px;
  }
  canvas {
    display: block;
    width: 100%;
  }
}
</style>
